<?php
/**
 * mc_import  载入包含文件
 *
 * @param filename    需要载入的文件名或者文件路径
 * @param auto_mc_error    自动提示扩展类载入出错信息
 */
function mc_import( $filename, $auto_mc_error = false ) {
    static $import = array();
    $key = md5( $filename );
    if ( isset( $import[ $key ] ) ) return true; // 已包含载入，返回
    // 检查$filename是否直接可读
    if ( true == @is_readable( $filename ) ) {
        require( $filename ); // 载入文件
        $import[ $key ] = true; // 对该文件进行标识为已载入
        return true;
    }
    $include_path = array( APP_PATH . '/system/core/', APP_PATH . '/system/lib/' );
    foreach ( $include_path as $path ) {
        // 检查当前搜索路径中，该文件是否已经载入
        if ( isset( $import[ $key ] ) ) return true;
        if ( is_readable( $path . $filename ) ) {
            require( $path . $filename ); // 载入文件
            $import[ $key ] = true; // 对该文件进行标识为已载入
            return true;
        }
    }
    if ( true == $auto_mc_error ) mc_error( "未能找到名为：{$filename}的文件" );
    return false;
}

/**
 * mc_class  类实例化函数  自动载入类定义文件，实例化并返回对象句柄
 *
 * @param class_name    类名称
 * @param args          类初始化时使用的参数，数组形式
 * @param path          载入类定义文件的路径，可以是目录+文件名的方式，也可以单独是目录
 * @param force_inst    是否强制重新实例化对象
 */
function mc_class( $class_name, $args = null, $path = null, $force_inst = false ) {
    static $classes = array();
    $key = null == $path ? $class_name : $path;
    // 检查类名称是否正确，以保证类定义文件载入的安全性
    if ( preg_match( '/[^a-z0-9\-_.]/i', $class_name ) ) mc_error( $class_name . "类名称错误，请检查。" );
    // 检查是否该类已经实例化，直接返回已实例对象，避免再次实例化
    if ( true != $force_inst ) if ( isset( $classes[ $key ] ) ) return $classes[ $key ];
    // 如果$path不能读取，则测试是否仅路径
    if ( null != $path && !mc_import( $path ) && !mc_import( $path . '/' . strtolower( $class_name ) . '.php' ) ) return false;

    $has_define = false;
    // 检查类定义是否存在
    if ( class_exists( $class_name, false ) || interface_exists( $class_name, false ) ) {
        $has_define = true;
    } else {
        if ( true == mc_import( strtolower( $class_name ) . '.php' ) ) {
            $has_define = true;
        }
    }
    if ( false != $has_define ) {
        $argString = '';
        $comma = '';
        if ( null != $args ) for ( $i = 0; $i < count( $args ); $i++ ) {
            $argString .= $comma . "\$args[$i]";
            $comma = ', ';
        }
        $classes[ $key ] = new $class_name( $argString );
        return $classes[ $key ];
    }
    mc_error( $class_name . "类定义不存在，请检查。" );
}

/**
 * mc_launch  执行扩展程序
 *
 * @param name     扩展程序设置点名称
 * @param args     扩展参数
 * @param returns  是否存在返回数据，如需要返回，则该扩展点仅能有一个扩展操作
 */
function mc_launch( $name, $args = null, $returns = false ) {
    static $launchs = array();
    if ( isset( $launchs[ $name ] ) && is_array( $launchs[ $name ] ) ) {
        foreach ( $launchs[ $name ] as $launch ) {
            if ( is_array( $launch ) ) {
                $reval = mc_class( $launch[ 0 ] )->{$launch[ 1 ]}( $args );
            } else {
                $reval = call_user_func_array( $launch, $args );
            }
            if ( TRUE == $returns ) return $reval;
        }
    }
    return false;
}

/*
 * 返回当前访问的文件名
 */
function mc_base() {
    if ( basename( $_SERVER[ 'SCRIPT_NAME' ] ) === basename( $_SERVER[ 'SCRIPT_FILENAME' ] ) ) {
        return $_SERVER[ 'SCRIPT_NAME' ];
    } elseif ( basename( $_SERVER[ 'PHP_SELF' ] ) === basename( $_SERVER[ 'SCRIPT_FILENAME' ] ) ) {
        return $_SERVER[ 'PHP_SELF' ];
    } elseif ( isset( $_SERVER[ 'ORIG_SCRIPT_NAME' ] ) && basename( $_SERVER[ 'ORIG_SCRIPT_NAME' ] ) === basename( $_SERVER[ 'SCRIPT_FILENAME' ] ) ) {
        return $_SERVER[ 'ORIG_SCRIPT_NAME' ];
    }
    return $_SERVER[ 'SCRIPT_NAME' ];
}

/**
 * mc_error 系统级错误提示
 *
 * @param msg    出错信息
 * @param stop    是否停止程序
 */
function mc_error( $msg, $stop = true ) {
    $traces = debug_backtrace();
    $bufferabove = ob_get_clean();
    require_once APP_PATH . "/system/core/error.php";
    if ( true == $stop ) exit;
}

/*
 * mc_request 获取应用程序请求变量值，同时也可以指定获取的变量所属。
 *
 * @param name       获取的变量名称，如果为空，则返回全部的请求变量
 * @param default    当前获取的变量不存在的时候，将返回的默认值
 */
function mc_request( $name, $deault = 0 ) {
    if ( $name == null ) {
        return $_REQUEST;
    }
    if ( isset( $_REQUEST[ $name ] ) ) {
        return $_REQUEST[ $name ];
    }
    if ( $deault ) {
        $_REQUEST[ $name ] = $deault;
        return $deault;
    }
    return false;
}

/*
 * mc_model   获取模型实例
 *
 * @param name       模型名称
 */
function mc_model( $name ) {
    $name = strtolower( $name );
    $model_file = APP_PATH . "/system/model/{$name}_model.php";
    if ( !is_readable( $model_file ) ) {
        mc_error( $model_file . " 模块文件不存在!" );
    }
    return mc_class( "{$name}_model", null, $model_file );
}

/**
 * mc_server     获取请求信息
 * @param a      请求参数
 */
function mc_server( $a = 'domain' ) {
    if ( $a == 'domain' ) {
        $http = ( isset( $_SERVER[ 'HTTPS' ] ) && $_SERVER[ 'HTTPS' ] != 'off' ) ? 'https://' : 'http://';
        return "{$http}{$_SERVER[ 'HTTP_HOST' ]}";
    }
    if ( $a == 'ip' ) {
        $ip = isset( $_SERVER[ 'REMOTE_ADDR' ] ) ? $_SERVER[ 'REMOTE_ADDR' ] : '';
        return mc_ip2long( $ip );
    }
    if ( isset( $_SERVER[ $a ] ) ) {
        return $_SERVER[ $a ];
    }
    return $_SERVER;
}

/**
 * mc_ip2long     将IP转换成数组
 * @param ip      要转换的IP地址
 */
function mc_ip2long( $ip ) {
    return bindec( decbin( ip2long( $ip ) ) );
}

/**
 * mc_blog_url     获取博客域名
 */
function mc_blog_url() {
    return mc_server();
}

/**
 * 返回指定的配置
 * @param key          系统配置变量
 */
function mc_setting( $key = null ) {
    if ( !defined( 'dbhost' ) ) return false;
    static $setting = array();
    if ( empty( $setting ) ) {
        $setting = mc_model( 'setting' )->get();
        @date_default_timezone_set( $setting[ 'timezone' ] ? $setting[ 'timezone' ] : 'PRC' );
    }
    if ( null == $key ) {
        return $setting;
    }
    if ( isset( $setting[ $key ] ) ) {
        return $setting[ $key ];
    }
    return false;
}

/**
 * mc_md5 数据加密
 * @param str         要加密的字符串
 * @param key         加密密匙
 * @param method      加密方法
 */
function mc_md5( $str = '', $method = 'md5', $key = null ) {
    if ( null == $key && defined( 'APP_KEY' ) ) $key = APP_KEY;
    $obj = mc_class( "encrypt" );
    $method = "_" . $method;
    return $obj->$method( $str, $key );
}

/*
 * 返回目录指定类型所有文件
 *
 * @param dir           文件目录
 * @param fileType      文件类型
 */
function mc_list_file( $dir, $fileType = "php" ) {
    $lists = glob( $dir . "*.{$fileType}" );
    return $lists;
}

/*
 * 返回目录下所有目录
 *
 * @param dir       文件目录
 */
function mc_list_dir( $dir ) {
    $lists = glob( $dir );
    foreach ( $lists as $k => $list ) {
        if ( !is_dir( $list ) ) {
            unset( $lists[ $k ] );
        } else {
            $lists[ $k ] = basename( $list );
        }
    }
    return $lists;
}

/**
 * rm               递遍历删除目录和目录下所有文件
 * @param dir      目录路径
 * @param flag     是否删除目录
 */
function mc_rm( $dir, $flag = true ) {
    if ( !is_dir( $dir ) ) {
        return false;
    }
    $handle = opendir( $dir );
    while ( ( $file = readdir( $handle ) ) !== false ) {
        if ( $file != "." && $file != ".." ) {
            is_dir( "$dir/$file" ) ? rm( "$dir/$file" ) : @unlink( "$dir/$file" );
        }
    }
    if ( readdir( $handle ) == false && $flag == true ) {
        closedir( $handle );
        @rmdir( $dir );
    }
}

/**
 * mc_mkdir           循环建立目录
 * @param  dir        目录路径
 */
function mc_mkdir( $dir ) {
    if ( !is_dir( $dir ) ) {
        mc_mkdir( dirname( $dir ) );
        umask( 0 );
        return @mkdir( $dir, 0777 );
    }
    return true;
}

/*
 * mc_is_writable_dir    检查目录是否可写
 * @param dir        要检查目录路径
 */
function mc_is_writable_dir( $dir ) {
    if ( !is_dir( $dir ) ) {
        @mkdir( $dir, 0777 );
    }
    if ( is_dir( $dir ) ) {
        if ( $fp = @fopen( "$dir/test.txt", 'w' ) ) {
            @fclose( $fp );
            @unlink( "$dir/test.txt" );
            return true;
        }
    }
    return false;
}

/**
 * formatFileSize        格式化文件大小
 * @param fileSize     原文件大小
 * @param len          小数点后的位数
 */
function mc_formatFileSize( $fileSize, $len = 2 ) {
    switch ( true ) {
        case $fileSize >= 1073741824 :
            return round( $fileSize / 1073741824, $len ) . 'GB';
        case $fileSize >= 1048576 :
            return round( $fileSize / 1048576, $len ) . 'MB';
        case $fileSize >= 1024 :
            return round( $fileSize / 1024, $len ) . 'KB';
        default :
            return $fileSize . '字节';
    }
    return $fileSize;
}

/**
 * formatDate     个性化时间
 * @param date     要被个性化的时间戳
 */
function mc_formatDate( $date ) {
    if ( !$date ) return '-';
    $sec = time() - $date;
    switch ( true ) {
        case $sec < 60:
            return $sec . '秒前';
        case $sec < 3600:
            return round( $sec / 60 ) . '分钟前';
        case $sec < 86400:
            return round( $sec / 3600 ) . '小时前';
        case $sec < ( 86400 * 7 ):
            return round( $sec / 86400 ) . '天前';
        case $sec < ( 86400 * 7 * 4 ):
            return round( $sec / ( 86400 * 7 ) ) . '周前';
        default:
            return date( "Y年n月d日", $date );
    }
}

/**
 * mc_substring 字符串截取，支持中文和其他编码
 * @param str     需要截取的字符串
 * @param start   开始位置
 * @param length  截取长度
 * @param charset 编码格式
 * @param suffix  截断字符串后缀
 */
function mc_substring( $str, $length, $start = 0, $suffix = "...", $charset = "utf-8" ) {
    if ( function_exists( "mb_substr" ) ) {
        return mb_substr( $str, $start, $length, $charset ) . $suffix;
    } elseif ( function_exists( 'iconv_substr' ) ) {
        return iconv_substr( $str, $start, $length, $charset ) . $suffix;
    }
    $re[ 'utf-8' ] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
    $re[ 'gb2312' ] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
    $re[ 'gbk' ] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
    $re[ 'big5' ] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
    preg_match_all( $re[ $charset ], $str, $match );
    $slice = join( "", array_slice( $match[ 0 ], $start, $length ) );
    return $slice . $suffix;
}

/**
 * mc_sort_key_array       对二维数组按指定key排序
 * @param arr          要排序的数组
 * @param key          需要排序的key
 * @param asc          升序or降序
 */
function mc_sort_key_array( $array, $key, $asc = true ) {
    $result = array();
    // 整理出准备排序的数组
    foreach ( $array as $k => $v ) {
        $values[ $k ] = isset( $v[ $key ] ) ? $v[ $key ] : '';
    }
    unset( $v );
    // 对需要排序键值进行排序
    $asc ? asort( $values ) : arsort( $values );
    // 重新排列原有数组
    foreach ( $values as $k => $v ) {
        $result[ $k ] = $array[ $k ];
    }
    return $result;
}

/**
 * mc_tree_array       对二维数组进行树形化
 * @param items        要树形的数组
 * @param id           父节点名称
 * @param pid          子节点名称
 */
function mc_tree_array( $items, $id = 'id', $pid = 'sid' ) {
    static $tree = array(); //格式化好的树
    foreach ( $items as $item ) {
        if ( isset( $items[ $item[ $pid ] ] ) ) {
            $items[ $item[ $pid ] ][ 'child' ][ ] = & $items[ $item[ $id ] ];
        } else {
            $tree[ $item[ $id ] ] = & $items[ $item[ $id ] ];
        }
    }
    return $tree;
}

/**
 * mc_unlimited_sort   无限级分类排序
 * @param items        要树形的数组
 * @param id           父节点名称
 * @param pid          子节点名称
 */
function mc_unlimited_sort( $result, $id = 0, $sid = "sid", $name = 'title', $icon = "├", $node = 0 ) {
    static $nodes = array();
    foreach ( $result as $v ) {
        if ( intval( $v[ $sid ] ) === intval( $id ) ) {
            $l = str_repeat( "&nbsp;&nbsp;", $node ) . ( $node ? $icon : "" );
            $v[ 'node' ] = $node;
            $v[ 'nodeTitle' ] = $l . $v[ $name ];
            $nodes[ $v[ 'id' ] ] = $v;
            mc_unlimited_sort( $result, $v[ 'id' ], $sid, $name, $icon, $node + 1 );
        }
    }
    return $nodes;

}

/**
 * mc_clear_html   清除HTML代码
 *
 * @param data   原HTML代码
 * @param line   是否清除换行回车制表符
 */
function mc_clear_html( $data, $line = false ) {
    $data = preg_replace( "/<[^>]+>/i", "", $data );
    if ( $line ) $data = str_replace( array( "\n", "\t", "\r" ), "", $data );
    return $data;
}

/*
 *  mc_thumb           生成图片缩略图 (宽和高都不=0时等比缩放有效, 否则按照宽高进行缩放)
 *  @param src_file    要生成缩略图文件
 *  @param rel_type    返回缩略图方式 0:绝对物理路径, 1: URL绝对路径
 *  @param thumbwidth  要生成缩略图宽度
 *  @param thumbheight 要生成缩略图高度
 */
function mc_thumb( $src_file, $thumbwidth = 220, $thumbheight = 0, $rel_type = 1 ) {
    return mc_class( 'Image' )->thumb( $src_file, $thumbwidth, $thumbheight, $rel_type );
}